DAO ガイド
このガイドでは、aos を使用して DAO を構築するプロセスを説明します。まだ行っていない場合は、最初に aos で トークン を構築する必要があります。DAO コードを aos に読み込み、トークン ガイドからトークンコードを読み込む予定です。ao の文脈では、DAO は MU、CU、および SU ノードを統治するために使用されることがあります。
私たちの DAO では、「スラッシング」と呼ばれるプロセスを実装します。ao の場合、ユニットが不正行為を行った場合、他のユニットはそれをスラッシュするために投票することができます。スラッシングとは、彼らが持っているステークを失うことを意味します。後でステークについて詳しく説明します。
dao
という新しいディレクトリを作成し、トークンガイドで作成した token.lua をコピーしてください。
mkdir dao
cd dao
cp ../token/token.lua .
今、dao.lua
という新しいファイルを作成し、お気に入りのエディタで開きます。
DAO コードを書く
状態の初期化
dao.lua
を開き、以下の行を追加します。
Balances = Balances or {}
Stakers = Stakers or {}
Unstaking = Unstaking or {}
Votes = Votes or {}
これらのテーブルは、ユーザーの残高、ステークされたトークン、アンステーキングリクエスト、投票記録など、DAO の状態を保存します。
ステーキング
ステーキングは、自分のトークンを預けるプロセスであり、投票する能力を与えます。誰かが投票する能力を得たい場合、彼らはトークンを所有し、ステークしなければなりません。ステーキングのためのハンドラーを追加しましょう。ao のメンバーやノードは、ノードをスラッシュするか維持するために投票する能力を得たい場合、ステークを希望します。これは後で詳しく説明します。
-- Stake Action Handler
Handlers.stake = function(msg)
local quantity = tonumber(msg.Tags.Quantity)
local delay = tonumber(msg.Tags.UnstakeDelay)
local height = tonumber(msg['Block-Height'])
assert(Balances[msg.From] and Balances[msg.From] >= quantity, "Insufficient balance to stake")
Balances[msg.From] = Balances[msg.From] - quantity
Stakers[msg.From] = Stakers[msg.From] or {}
Stakers[msg.From].amount = (Stakers[msg.From].amount or 0) + quantity
Stakers[msg.From].unstake_at = height + delay
end
上記のコードは、受信したメッセージから数量と遅延を取得し、もし送信者に十分な残高があれば、ステークを Stakers テーブルに追加します。遅延は、トークンがアンステークされる未来の時間を表します。
アンステーキング
アンステーキングは、ステークされたトークンを引き出すプロセスです。誰かがすべてのトークンをアンステークすると、彼らは投票する能力を放棄することになります。ここでは、アンステーキングのためのハンドラーを提供します。
-- Unstake Action Handler
Handlers.unstake = function(msg)
local quantity = tonumber(msg.Tags.Quantity)
local stakerInfo = Stakers[msg.From]
assert(stakerInfo and stakerInfo.amount >= quantity, "Insufficient staked amount")
stakerInfo.amount = stakerInfo.amount - quantity
Unstaking[msg.From] = {
amount = quantity,
release_at = stakerInfo.unstake_at
}
end
これにより、受信した金額を Unstaking テーブルに追加し、彼らのステークされた金額を減少させます。stakerInfo.amount = stakerInfo.amount - quantity
。
投票
投票は DAO を統治するプロセスです。投票メッセージが送信されると、メンバーは彼らがステークした量に比例した投票を受け取ります。デッドライン変数は、投票が適用される時刻を表します。
-- Vote Action Handler
Handlers.vote = function(msg)
local quantity = Stakers[msg.From].amount
local target = msg.Tags.Target
local side = msg.Tags.Side
local deadline = tonumber(msg['Block-Height']) + tonumber(msg.Tags.Deadline)
assert(quantity > 0, "No staked tokens to vote")
Votes[target] = Votes[target] or { yay = 0, nay = 0, deadline = deadline }
Votes[target][side] = Votes[target][side] + quantity
end
ここでは、投票を送信するプロセスまたはユーザーがトークンを持っている場合、Votes テーブルにエントリを追加できます。side
の yay または nay は、彼らのステークの量に設定されます。例として、"nay" 投票はスラッシュする投票であり、"yay" 投票は維持する投票です。
送信された msg.Tags.Target は、投票される対象を表します。AO の場合、これはメンバーがスラッシュすることに投票している MU、CU、または SU のウォレットアドレスである可能性があります。
最終化
すべてのメッセージに対して実行したいロジックがあります。これを finalizationHandler
として定義します。スラッシュされるということは、DAO 内でのステークを失うことを意味します。
-- Finalization Handler
local finalizationHandler = function(msg)
local currentHeight = tonumber(msg['Block-Height'])
-- Process unstaking
for address, unstakeInfo in pairs(Unstaking) do
if currentHeight >= unstakeInfo.release_at then
Balances[address] = (Balances[address] or 0) + unstakeInfo.amount
Unstaking[address] = nil
end
end
-- Process voting
for target, voteInfo in pairs(Votes) do
if currentHeight >= voteInfo.deadline then
if voteInfo.nay > voteInfo.yay then
-- Slash the target's stake
local slashedAmount = Stakers[target] and Stakers[target].amount or 0
Stakers[target].amount = 0
end
-- Clear the vote record after processing
Votes[target] = nil
end
end
end
受信メッセージタグへのハンドラーの添付
ここでは、すべてのメッセージに対して finalizationHandler
まで実行できるヘルパー関数 continue
を追加します。
最後に、すべてのハンドラーを登録し、各 Stake、Unstake、および Vote メッセージに対して常に finalizationHandler に到達できるように continue
でラップします。
-- wrap function to continue handler flow
function continue(fn)
return function (msg)
local result = fn(msg)
if (result) == -1 then
return 1
end
return result
end
end
最後に、すべてのハンドラーを登録し、それらを continue でラップして、すべての Stake、Unstake、Vote メッセージに対して常に finalizationHandler に到達できるようにします。
-- Registering Handlers
Handlers.add("stake",
continue(Handlers.utils.hasMatchingTag("Action", "Stake")), Handlers.stake)
Handlers.add("unstake",
continue(Handlers.utils.hasMatchingTag("Action", "Unstake")), Handlers.unstake)
Handlers.add("vote",
continue(Handlers.utils.hasMatchingTag("Action", "Vote")), Handlers.vote)
-- Finalization handler should be called for every message
Handlers.add("finalize", function (msg) return -1 end, finalizationHandler)
読み込みとテスト
dao.lua
が完成したので、これをトークンガイドの token.lua
とともに aos に読み込むことができます。dao
という新しい aos プロセスを実行し、dao.lua
と token.lua
を読み込みます。
aos dao --load token.lua --load dao.lua
別のターミナルから、voterという名前の別の aos プロセスを実行します。
aos voter
次に、dao aos シェルからその voter にいくつかのトークンを送信します。
Send({ Target = ao.id, Tags = { Action = "Transfer", Recipient = 'process id of the voter aos', Quantity = '100000' }})
別のターミナルから、cuという名前の別の aos プロセスを実行します。
aos cu
次に、dao aos シェルからその cu にいくつかのトークンを送信します。
Send({ Target = ao.id, Tags = { Action = "Transfer", Recipient = 'process id of the cu aos', Quantity = '100000' }})
Check the Balances from the dao aos shell, we should see a balance for the voter and cu Process. In the below examples bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s
is the dao aos, QcGIOXJ1p2SOGzGAccOcV-nSudVRiaPYbU7SjeLx1OE
is the voter aos, and X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s
is the cu aos.
Balances
{
'QcGIOXJ1p2SOGzGAccOcV-nSudVRiaPYbU7SjeLx1OE': 100000,
bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s: 99999999900000,
X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s: 100000
}
voter aos プロセスから、いくつかのトークンをステークします。
Send({ Target = "bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s", Tags = { Action = "Stake", Quantity = '1000', UnstakeDelay = "10" }})
cu aos プロセスから、いくつかのトークンをステークします。
Send({ Target = "bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s", Tags = { Action = "Stake", Quantity = '1000', UnstakeDelay = "10" }})
これは、10 ブロックの間に 1000 トークンをステークすることを意味します。したがって、10 ブロック後にアンステークする能力が得られます。
dao aos シェルから Stakers テーブルの値を確認します。
Stakers
{
'QcGIOXJ1p2SOGzGAccOcV-nSudVRiaPYbU7SjeLx1OE': { amount: 1000, unstake_at: 1342634 },
X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s: { amount: 1000, unstake_at: 1342634 }
}
次に、voter aos プロセスから cu をスラッシュするための投票を行います。私たちの投票は 1 ブロック後に効力を発揮します。
Send({ Target = "bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s", Tags = { Action = "Vote", Target = "X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s(the cu aos)", Side = "nay", Deadline = "1" }})
From the dao aos check the Votes
Votes
{
X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s: { nay: 1000, yay: 0, deadline: 1342627 }
}
次に、Arweave が締切の block height に達するのを待ってから、dao aos からステークメッセージを送信して finalizationHandler をトリガーします。 block height は https://arweave.net/ で確認できます。
Send({ Target = ao.id, Tags = { Action = "Stake", Quantity = '1000', UnstakeDelay = "10" }})
Votes と Stakers を確認します。Votes は空で、cu aos プロセスはステークを失っているはずです。
Votes
[]
Stakers
{
'QcGIOXJ1p2SOGzGAccOcV-nSudVRiaPYbU7SjeLx1OE'(voter aos process): { amount: 1000, unstake_at: 1342647 },
bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s(dao aos process): { amount: 1000, unstake_at: 1342658 },
X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s(cu aos process): { amount: 0, unstake_at: 1342647 }
}
最後に、voter aos プロセスからトークンのアンステークを行います。
Send({ Target = "bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s", Tags = { Action = "Unstake", Quantity = '1000'}})
そして、dao aos から Stakers テーブルを確認します。
Stakers
{
'QcGIOXJ1p2SOGzGAccOcV-nSudVRiaPYbU7SjeLx1OE': { amount: 0, unstake_at: 1342647 },
bclTw5QOm5soeMXoaBfXLvzjheT1_kwc2vLfDntRE4s: { amount: 1000, unstake_at: 1342658 },
X6mkYwt87mIsfsQzDAJr54S0BBxLrDwWMdq7seBcS6s: { amount: 0, unstake_at: 1342647 }
}
これで DAO ガイドは終了です。お役に立てたことを願っています!